package com.bicon.botu.core.base.common.utils;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dozer.DozerBeanMapper;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现:
 * <p>
 * 1. 持有Mapper的单例. 2. 返回值类型转换. 3. 批量转换Collection中的所有对象. 4.
 * 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数.
 *
 * @author calvin
 */
public class BeanMapper {

    /**
     * 持有Dozer单例, 避免重复创建DozerMapper消耗资源.
     */
    private static DozerBeanMapper dozer = new DozerBeanMapper();

    /**
     * 基于Dozer转换对象的类型.
     */
    public static <T> T map(Object source, Class<T> destinationClass) {
        return dozer.map(source, destinationClass);
    }

    /**
     * 基于Dozer转换Collection中对象的类型.
     */
    public static <T> List<T> mapList(
            @SuppressWarnings("rawtypes") Collection sourceList,
            Class<T> destinationClass) {
        List<T> destinationList = new ArrayList<T>();
        for (Object sourceObject : sourceList) {
            T destinationObject = dozer.map(sourceObject, destinationClass);
            destinationList.add(destinationObject);
        }
        return destinationList;
    }

    /**
     * 基于Dozer将对象A的值拷贝到对象B中.
     */
    public static void copy(Object source, Object destinationObject) {
        dozer.map(source, destinationObject);
    }

    /**
     * 将beam转换为String Map
     * @param bean
     * @param <T>
     * @return
     */
    public static <T> Map<String, String> convetToStringMap(T bean) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        JsonNode node = mapper.valueToTree(bean);
        Map<String, String> result = new HashMap<String, String>();
        Iterator<String> iterator = node.fieldNames();
        while (iterator.hasNext()) {
            String key = iterator.next();
            result.put(key, node.get(key).toString());
        }

        return result;
    }


    /**
     * getFileds获取所有public 属性<br/>
     * getDeclaredFields 获取所有声明的属性<br/>
     *
     * @param bean
     * @return 将某个类及其继承属性全部添加到Map中
     */
    public static Map<String, Object> beanToMap(Object bean) {
        Map<String, Object> result = new HashMap<String, Object>();
        if (bean == null) {
            return result;
        }

        Field[] fields = bean.getClass().getDeclaredFields();
        if (fields == null || fields.length == 0) {
            return result;
        }

        result.putAll(BeanMapper.getAllFieldMap(bean,fields));

        //获取父类属性
        fields = bean.getClass().getSuperclass().getDeclaredFields();
        if (fields == null || fields.length == 0) {
            return result;
        }
        result.putAll(BeanMapper.getAllFieldMap(bean,fields));
        return result;
    }

    /**
     * 将bean的部分字段转换为Map
     * @param bean
     * @param fields
     * @return
     */
    public static Map<String, Object> getAllFieldMap(Object bean,Field[] fields){
        Map<String, Object> result = new HashMap<String, Object>();
        for (Field field : fields) {
            //重置属性可见(而且一般属性都是私有的)，否则操作无效
            boolean accessible = field.isAccessible();
            if (!accessible) {
                field.setAccessible(true);
            }

            //获取属性名称及值存入Map
            String key = field.getName();
            try {
                result.put(key, field.get(bean));
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            //还原属性标识
            field.setAccessible(accessible);
        }
        return result;
    }
}